﻿#region Copyright
//————————————————————————————————————————//
//	创建人员(Creator)    ：Huangyd
//	创建日期(Date)       ：2012-07-03
//  联系方式(Email)      ：aj-ayumi@163.com; gajayumi@gmail.com; ajayumi@me.com
//  描    述(Description)：
//
//	Copyright (C) 2012 ajayumi 版权所有
//————————————————————————————————————————//
#endregion
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Data;
using System.Data.OleDb;
using System.Security.Permissions;
using System.Web;

/*
<configuration>
  <system.web>
    <siteMap defaultProvider="AccessSiteMapProvider">
     <providers>
       <add 
         name="AccessSiteMapProvider"
         type="Samples.AspNet.AccessSiteMapProvider,Samples.AspNet "
         accessSiteMapConnectionString="PROVIDER=MICROSOFT.JET.OLEDB.4.0;DATA SOURCE=sitemap.mdb "/>
     </providers> 
    </siteMap>
  </system.web>
</configuration>
 */

namespace ajayumi.Platform.Web.SiteMapProvider
{
    /// <summary>
    /// AccessSiteMapProvider 类是从 StaticSiteMapProvider 类派生的，
    /// 它使用基本的 SQL 查询以及 OleDbCommand 和 OleDbDataReader 对象从 Microsoft Access 数据库检索其信息。
    /// </summary>
    [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class AccessSiteMapProvider : StaticSiteMapProvider
    {
        private SiteMapNode rootNode = null;
        private OleDbConnection accessConnection = null;

        // This string is case sensitive.

        private string AccessConnectionStringName = "accessSiteMapConnectionString";

        // Implement a default constructor.

        public AccessSiteMapProvider() { }

        // Some basic state to help track the initialization state of the provider.

        private bool initialized = false;
        public virtual bool IsInitialized
        {
            get
            {
                return initialized;
            }
        }
        // Return the root node of the current site map.

        public override SiteMapNode RootNode
        {
            get
            {
                SiteMapNode temp = null;
                temp = BuildSiteMap();
                return temp;
            }
        }
        protected override SiteMapNode GetRootNodeCore()
        {
            return RootNode;
        }
        // Initialize is used to initialize the properties and any state that the

        // AccessProvider holds, but is not used to build the site map.

        // The site map is built when the BuildSiteMap method is called.

        public override void Initialize(string name, NameValueCollection attributes)
        {
            if (IsInitialized)
                return;

            base.Initialize(name, attributes);

            // Create and test the connection to the Microsoft Access database.


            // Retrieve the Value of the Access connection string from the

            // attributes NameValueCollection.

            string connectionString = attributes[AccessConnectionStringName];

            if (null == connectionString || connectionString.Length == 0)
                throw new Exception("The connection string was not found.");
            else
                accessConnection = new OleDbConnection(connectionString);

            initialized = true;
        }

        ///

        /// SiteMapProvider and StaticSiteMapProvider methods that this derived class must override.

        ///

        // Clean up any collections or other state that an instance of this may hold.

        protected override void Clear()
        {
            lock (this)
            {
                rootNode = null;
                base.Clear();
            }
        }

        // Build an in-memory representation from persistent

        // storage, and return the root node of the site map.

        public override SiteMapNode BuildSiteMap()
        {

            // Since the SiteMap class is static, make sure that it is

            // not modified while the site map is built.

            lock (this)
            {

                // If there is no initialization, this method is being

                // called out of order.

                if (!IsInitialized)
                {
                    throw new Exception("BuildSiteMap called incorrectly.");
                }

                // If there is no root node, then there is no site map.

                if (null == rootNode)
                {
                    // Start with a clean slate

                    Clear();

                    // Select the root node of the site map from Microsoft Access.

                    int rootNodeId = -1;

                    if (accessConnection.State == ConnectionState.Closed)
                        accessConnection.Open();
                    OleDbCommand rootNodeCommand =
                        new OleDbCommand("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid IS NULL",
                                         accessConnection);
                    OleDbDataReader rootNodeReader = rootNodeCommand.ExecuteReader();

                    if (rootNodeReader.HasRows)
                    {
                        rootNodeReader.Read();
                        rootNodeId = rootNodeReader.GetInt32(0);
                        // Create a SiteMapNode that references the current StaticSiteMapProvider.

                        rootNode = new SiteMapNode(this,
                                                     rootNodeId.ToString(),
                                                     rootNodeReader.GetString(1),
                                                     rootNodeReader.GetString(2));

                    }
                    else return null;

                    rootNodeReader.Close();
                    // Select the child nodes of the root node.

                    OleDbCommand childNodesCommand =
                        new OleDbCommand("SELECT nodeid, url, name FROM SiteMap WHERE parentnodeid = ?",
                                         accessConnection);
                    OleDbParameter rootParam = new OleDbParameter("parentid", OleDbType.Integer);
                    rootParam.Value = rootNodeId;
                    childNodesCommand.Parameters.Add(rootParam);

                    OleDbDataReader childNodesReader = childNodesCommand.ExecuteReader();

                    if (childNodesReader.HasRows)
                    {

                        SiteMapNode childNode = null;
                        while (childNodesReader.Read())
                        {
                            childNode = new SiteMapNode(this,
                                                         childNodesReader.GetInt32(0).ToString(),
                                                         childNodesReader.GetString(1),
                                                         childNodesReader.GetString(2));

                            // Use the SiteMapNode AddNode method to add

                            // the SiteMapNode to the ChildNodes collection.

                            AddNode(childNode, rootNode);
                        }
                    }

                    childNodesReader.Close();
                    accessConnection.Close();
                }
                return rootNode;
            }
        }
    }

}
